package com.yang.core.service;

import com.querydsl.core.Tuple;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.yang.core.dao.ProductImageRepository;
import com.yang.core.dao.ScarRepository;
import com.yang.core.model.*;
import com.yang.core.model.bo.CarItemBO;
import com.yang.service.api.ScarService;
import com.yang.service.model.dto.post.ScarPostDTO;
import com.yang.service.model.vo.ProductVO;
import com.yang.service.model.vo.ScarVO;
import com.zhy.base.jpa.order.OrderHandler;
import com.zhy.base.tools.beans.BeanMapper;
import com.zhy.base.tools.em.YesOrNo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.web.bind.annotation.*;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by xin7k
 * Date: 2019/12/2
 */
@Slf4j
@RestController
@RequestMapping("scar")
@Api(tags = "购物车操作API", description = "scar")
public class ScarServiceImpl implements ScarService {

    @Autowired
    private BeanMapper beanMapper;
    @Autowired
    private ProductImageRepository productImageRepository;
    @Autowired
    private ScarRepository scarRepository;
    @Autowired
    private JPAQueryFactory queryFactory;

    @ApiOperation("通过userId获取所有购物车")
    @GetMapping("list")
    @Transactional
    @Override
    public List<ScarVO> getAllScar(String userId) {
        //TODO 修改一下返回了所有图片的BUG，并且在每个商品的List里面加入一个字段 scarId 就是每个购物车的id
        //1. 定义select范围
        JPAQuery<Tuple> select = queryFactory.select(QShop.shop.id, QShop.shop.shopName, QProduct.product);
        //2. 定义from and inner join范围和条件
        JPAQuery<Tuple> tupleQuery = select.from(QScar.scar)
                .innerJoin(QProduct.product).on(QProduct.product.id.eq(QScar.scar.productId))
                .innerJoin(QShop.shop).on(QShop.shop.id.eq(QProduct.product.shopId))
                .innerJoin(QUser.user).on(QUser.user.id.eq(QScar.scar.userId));
        //3. 定义where
        BooleanExpression where = QUser.user.id.eq(userId)
                .and(QScar.scar.isDeleted.eq(YesOrNo.NO.getCode()))
                .and(QProduct.product.isDeleted.eq(YesOrNo.NO.getCode()))
                .and(QShop.shop.isDeleted.eq(YesOrNo.NO.getCode()))
                .and(QUser.user.isDeleted.eq(YesOrNo.NO.getCode()));
        tupleQuery = tupleQuery.where(where);
        //4. 获取结果
        List<Tuple> tupleResult = tupleQuery.fetch();

        // 以上4个步骤也能合并成一行，但是要记住具体的使用方式
//        List<Tuple> tupleResult = queryFactory.select(QShop.shop.shopName, QProduct.product)
//                .from(QScar.scar)
//                .innerJoin(QProduct.product).on(QProduct.product.id.eq(QScar.scar.productId))
//                .innerJoin(QShop.shop).on(QShop.shop.id.eq(QProduct.product.shopId))
//                .innerJoin(QUser.user).on(QUser.user.id.eq(QScar.scar.userId))
//                .where(QUser.user.id.eq(userId)
//                        .and(QScar.scar.isDeleted.eq(YesOrNo.NO.getCode()))
//                        .and(QProduct.product.isDeleted.eq(YesOrNo.NO.getCode()))
//                        .and(QShop.shop.isDeleted.eq(YesOrNo.NO.getCode()))
//                        .and(QUser.user.isDeleted.eq(YesOrNo.NO.getCode())))
//                .fetch();

        //5. 从结果取数据
        if (CollectionUtils.isNotEmpty(tupleResult)){
            Map<String, List<CarItemBO>> map = tupleResult.stream()
                    .map(t -> {
                        //查询产品图片（通常建议一次查询所需全部，不要这样在循环中查询）
                        List<ProductImage> productImages = productImageRepository.selectAll(Example.of(new ProductImage(t.get(QProduct.product.id))), OrderHandler.getSort(ProductImage.class));

                        //通过tuple对象get方法获取值, 获取值和[1.定义select范围]对应
                        Product product = t.get(QProduct.product);
                        CarItemBO bo = beanMapper.map(product, CarItemBO.class);
                        bo.setShopId(t.get(QShop.shop.id));
                        bo.setShopName(t.get(QShop.shop.shopName));
                        bo.setProductImgs(productImages.stream().map(ProductImage :: getImgAddr).collect(Collectors.toList()));
                        return bo;
                    })
                    //按照店铺分组得到Map<String, List<CarItemBO>>， key: 店铺id  value：该店铺所有的产品
                    .collect(Collectors.groupingBy(CarItemBO :: getShopId));

            //封装List<ScarVO>数据并返回
            List<ScarVO> vos = Lists.newArrayList();
            map.forEach((k, v) -> {
                ScarVO vo = new ScarVO();
                vo.setProductList(beanMapper.mapList(v, ProductVO.class));
                vo.setShopId(k);
                vo.setShopName(v.get(0).getShopName());
                vos.add(vo);
            });
            return vos;
        }
        return Lists.newArrayList();
    }

    @ApiOperation("新增购物车")
    @PostMapping()
    @Transactional
    @Override
    public boolean addScar(ScarPostDTO dto) {
        Scar scar = new Scar();
        scar.setUserId(dto.getUserId());
        scar.setProductId(dto.getProductId());
        Scar save = scarRepository.save(scar);
        return save!=null;
    }

    @ApiOperation("批量删除购物车")
    @DeleteMapping("batch")
    @Transactional
    @Override
    public boolean deleteBatch(List<String> oderIds) {
        for(int i = 0; i < oderIds.size(); i++){
            scarRepository.deleteById(oderIds.get(i));
        }
        return true;
    }


}
